#region Microsoft Public License
/*
 * (c) Copyright Chenjun Wu. http://utablesdk.codeplex.com
 * 
 * This source is subject to the Microsoft Public License (Ms-PL).
 * Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
 * All other rights reserved.
 */
#endregion

using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using MultipleMice;
using Multitouch.Contracts;
using UTable.Input.MultiTouch;

namespace UTable.Input
{
	public class MultiMouseProvider : Grid, IInputProvider
	{
        private Window currentWindow;
        private int _id = 0;

        public MultiMouseProvider()
        {
            // Move system cursor to a fixed location so it doesn't cause any trouble
            // MultiPointSDK.SystemCursorPosition = new Point(10, 10);
            // Hide the system cursor
            // MultiPointSDK.HideSystemCursor();
        }

        public Window CurrentWindow 
        {
            set
            {
                currentWindow = value;
                InputProvider provider = new InputProvider();
                provider.Start();
                provider.NewFrame += new EventHandler<Multitouch.Contracts.NewFrameEventArgs>(provider_NewFrame);
                Mouse.OverrideCursor = Cursors.None;
            }
            get
            {
                return currentWindow;
            }
        }

        private int DeviceId
        {
            get { return _id; }
            set { _id = value; }
        }

		#region Events Process

        void provider_NewFrame(object sender, Multitouch.Contracts.NewFrameEventArgs e)
        {
            Collection<Contact> contacts = new Collection<Contact>();

            foreach (Contact contact in e.Contacts)
            {
                // Console.WriteLine(contact.Position + ", " + contact.State + ", " + contact.Id);
                contacts.Add(contact);
            }

            currentWindow.Dispatcher.BeginInvoke(new OnContactsReceivedHandler(this.OnContactsReceived), new object[] { contacts });
        }

        delegate void OnContactsReceivedHandler(Collection<Contact> contacts);

        void OnContactsReceived(Collection<Contact> contacts)
        {
            foreach (Contact contact in contacts)
            {
                switch (contact.State)
                {
                    case ContactState.Moved:
                        OnMultiPointMouseMove(contact);
                        break;
                    case ContactState.New:
                        OnMultiPointMouseLeftButtonDown(contact);
                        break;
                    case ContactState.Removed:
                        OnMultiPointMouseLeftButtonUp(contact);
                        break;
                }
            }
        }

		/// <summary>
		///  This method is called by MultiPointMouseLeftButtonDown Event Handler
		/// </summary>
		/// <param name="sender">MultiPointCheckBox</param>
		/// <param name="e">RoutedEvent Data</param>
        void OnMultiPointMouseLeftButtonDown(Contact contact)
		{
            //Console.WriteLine("Mouse Left Button Down");
			FingerEventArgs finger_event = new FingerEventArgs();
            finger_event.Timestamp = InputEventArgs.GetTimestamp();
			finger_event.FingerID = contact.Id;
			finger_event.EventType = FingerEventType.FINGER_DOWN_EVENT;
            Point p = new Point(contact.Position.X, contact.Position.Y);
            //Point p = this.PointFromScreen(contact.Position);
            //p = CurrentWindow.TranslatePoint(p, this);
            finger_event.Position = p;
			finger_event.GlobalPosition = p;
            finger_event.SourceID = DeviceId;
            finger_event.UserID = 999;
            finger_event.DeviceName = this.GetType().ToString();
			Collection<FingerEventArgs> event_colection = new Collection<FingerEventArgs>();
			event_colection.Add(finger_event);
            //TODO will here event_collection.Count be more than 1?
			MultiTouchEventArgs multitouch_event = new MultiTouchEventArgs(event_colection, InputEventArgs.GetTimestamp());
            if (InputTriggered != null)
			    InputTriggered(multitouch_event);
		}

		/// <summary>
		/// This method is called by MultiPointMouseLeftButtonUp handler
		/// </summary>
		/// <param name="sender">MultiPointCheckBox</param>
		/// <param name="e">RoutedEvent Data</param>
        void OnMultiPointMouseLeftButtonUp(Contact contact)
		{
            //Console.WriteLine("Mouse Left Button Up");
			FingerEventArgs finger_event = new FingerEventArgs();
            finger_event.Timestamp = InputEventArgs.GetTimestamp();
            finger_event.FingerID = contact.Id;
			finger_event.EventType = FingerEventType.FINGER_UP_EVENT;
            Point p = this.PointFromScreen(contact.Position);
            p = CurrentWindow.TranslatePoint(p, this);
            finger_event.Position = p;
            finger_event.GlobalPosition = p;
            finger_event.SourceID = DeviceId;
            finger_event.UserID = 999;
            finger_event.DeviceName = this.GetType().ToString();
			Collection<FingerEventArgs> event_colection = new Collection<FingerEventArgs>();
			event_colection.Add(finger_event);
			MultiTouchEventArgs multitouch_event = new MultiTouchEventArgs(event_colection, InputEventArgs.GetTimestamp());
            if (InputTriggered != null)
                InputTriggered(multitouch_event);
		}

		/// <summary>
		/// This method is called by MultiPointMouseMove handler
		/// </summary>
		/// <param name="sender">MultiPointCheckBox</param>
		/// <param name="e">RoutedEvent Data</param>
        void OnMultiPointMouseMove(Contact contact)
		{
			FingerEventArgs finger_event = new FingerEventArgs();
            finger_event.Timestamp = InputEventArgs.GetTimestamp();
            finger_event.FingerID = contact.Id;
			finger_event.EventType = FingerEventType.FINGER_MOVE_EVENT;
            Point p = this.PointFromScreen(contact.Position);
            p = CurrentWindow.TranslatePoint(p, this);
            finger_event.Position = p;
            finger_event.GlobalPosition = p;
            finger_event.SourceID = DeviceId;
            finger_event.UserID = 999;
            finger_event.DeviceName = this.GetType().ToString();
			Collection<FingerEventArgs> event_colection = new Collection<FingerEventArgs>();
			event_colection.Add(finger_event);
			MultiTouchEventArgs multitouch_event = new MultiTouchEventArgs(event_colection, InputEventArgs.GetTimestamp());
            if (InputTriggered != null)
			    InputTriggered(multitouch_event);
		}

		#endregion

		#region IInputProvider Members

        public event InputEventHandler InputTriggered;

        public void Initialize(UTable.Objects.UApplication context)
        {
            this.CurrentWindow = context.MainWindow;
            context.Host.Children.Add(this);
        }

		#endregion
	}
}

